package run.halo.app.LYFtool;

import java.util.Arrays;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


@Aspect
@Slf4j
@Component
public class LOG {

    @Around("within(run.halo.app.controller..*)")
    public Object urlLog(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes =
            (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Signature signature = joinPoint.getSignature();
        log.info("\nurl:{}\n{}\n参数\n{}\n",
            request.getRequestURI(),
            ideaLink(joinPoint),
            joinPoint.getArgs()
        );
        Object res = joinPoint.proceed();
        log.info("\nurl:{}\n{}\nresult\n{}\n",
            request.getRequestURI(),
            ideaLink(joinPoint),
            res
        );
        return res;
    }

    //TODO LYF 构造idea链接
    String ideaLink(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        String className = signature.getDeclaringTypeName();
        String methodName = signature.getName();
        String fileName = className.substring(className.lastIndexOf('.') + 1) + ".java";
        int lineNo = getLineNo(className, methodName, getParaTypeName(signature));
        return String.format("at %s.%s(%s:%d)", className, methodName, fileName, lineNo);
    }

    //TODO LYF 获取对应方法参数完全限定名
    String[] getParaTypeName(Signature signature) {
        String longName = signature.toLongString();
        return longName.substring(longName.indexOf("(") + 1, longName.length() - 1).split(",");
    }

    //TODO LYF 获取对应方法行号
    int getLineNo(String className, String methodName, String[] paraNames) {
        try {
            CtClass cc = getCtClass(className);
            CtMethod methodX = null;
            if (StringUtils.isBlank(paraNames[0])) {
                methodX = cc.getDeclaredMethod(methodName);
            } else {
                methodX = cc.getDeclaredMethod(methodName,
                    Arrays.stream(paraNames).map(this::getCtClass).toArray(CtClass[]::new));
            }
            return methodX.getMethodInfo().getLineNumber(0);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
        return 0;
    }

    ClassPool pool = ClassPool.getDefault();

    //TODO LYF 把完全限定名转化为CtClass
    CtClass getCtClass(String className) {
        try {
            return pool.get(className);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
